﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using MPI;

namespace Dwarf.Managed
{
    /// <summary>
    /// User interface for solving the Dense Linear Algebra Problem.
    /// </summary>
    class Program
    {
        /// <summary>
        /// The settings for this dwarf.
        /// </summary>
        static private Settings settings;

        /// <summary>
        /// Get settings from the command line.
        /// </summary>
        /// <param name="args">
        /// Cli params.
        /// </param>
        /// <param name="dlasolver">
        /// Instance of Solver.
        /// </param>
        static void getSettings(String[] args, Solver dlasolver)
        {
            bool error = false;
            if (Communicator.world.Rank == Solver.ROOT_PROCESS)
            {
                try
                {
                    settings = new Settings();
                    settings.Init(args, dlasolver); //Parse all arguments for dwarf.
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    error = true;
                }
            }

            //Distribute error if that occurred while parsing.
            MPI.Communicator.world.Broadcast(ref error, Solver.ROOT_PROCESS);
            if (error) throw new Exception("");

            //Distribute size of matrices.
            MPI.Communicator.world.Broadcast(ref dlasolver.msize, Solver.ROOT_PROCESS);

            //Init matrices.
            if (Communicator.world.Rank != Solver.ROOT_PROCESS)
            {
                dlasolver.rgrid = new double[dlasolver.msize][];
                for (int i = 0; i < dlasolver.msize; i++)
                {
                    dlasolver.rgrid[i] = new double[dlasolver.msize];
                }

                dlasolver.lgrid = new double[1][];
                dlasolver.lgrid[0] = new double[dlasolver.msize];

                dlasolver.result = new double[1][];
                dlasolver.result[0] = new double[dlasolver.msize];
            }

            //Distribute right matrix to all.
            for (int i = 0; i < dlasolver.msize; i++)
            {
                Communicator.world.Broadcast(ref dlasolver.rgrid[i], Solver.ROOT_PROCESS);
            }
        }

        /// <summary>
        /// Point of the program start.
        /// </summary>
        /// <param name="args">
        /// Cli params.
        /// </param>
        static void Main(String[] args)
        {
            try
            {
                using (new MPI.Environment(ref args))                       // MPI Initialization.
                {
                    if (Communicator.world.Size == 1)
                    {
                        throw new Exception("Only one mpi process.");
                    }

                    Solver dlasolver = new Solver();

                    getSettings(args, dlasolver);                           // Get settings from the command line.

                    Communicator.world.Barrier();
                    if (Communicator.world.Rank == Solver.ROOT_PROCESS)
                        settings.Start();                                   // Start new time count.
                    dlasolver.Solve();                                      // Solve the current problem.
                    Communicator.world.Barrier();
                    if (Communicator.world.Rank == Solver.ROOT_PROCESS)
                        settings.Finish(dlasolver);                         // Stop the time count and write results.
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                //usage();
            }
        }
    }
}
